package com.wisdom.system.api.core.aop;


import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.wisdom.system.common.annotation.ValidationUnique;
import com.wisdom.system.common.util.StringUtil;
import com.wisdom.system.service.MIService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.PriorityOrdered;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.persistence.Column;
import javax.persistence.Table;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

@Aspect
@Component
public class ServiceAspect implements PriorityOrdered {

    @Autowired
    private MIService miService;
    /**
     * 定义一个切入点表达是，用来定义哪些类需要代理
     */
    @Pointcut("execution(* com.wisdom.system.service.impl.*.*.*(..))")
    public void declareJoinPointerExpression() {
    }

    @Around("declareJoinPointerExpression()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        if (RequestContextHolder.getRequestAttributes() != null) {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            if ("POST".equalsIgnoreCase(request.getMethod()) || "PUT".equalsIgnoreCase(request.getMethod())) {
                Object target = pjp.getTarget();
                String methodName = pjp.getSignature().getName();
                Class[] parameterTypes = ((MethodSignature) pjp.getSignature()).getMethod().getParameterTypes();
                HashMap<String, Object> map = new HashMap<>();
                //获取表名
                String tableName = "";
                if (parameterTypes != null && parameterTypes.length > 0) {
                    //获取参数类上的注解
                    boolean clazzHasAnnotation = parameterTypes[0].isAnnotationPresent(Table.class);
                    if (clazzHasAnnotation) {
                        //获取列上的注解
                        Table tableAnnotation = (Table) parameterTypes[0].getAnnotation(Table.class);
                        tableName = tableAnnotation.name();
                        map.put("table", tableName);
                    }
                    Field[] fields = parameterTypes[0].getDeclaredFields();
                    Method method = target.getClass().getMethod(methodName, parameterTypes);
                    boolean isValidation = method.isAnnotationPresent(ValidationUnique.class);
                    if (isValidation) {
                        //参数对象值
                        JsonObject paramValueInfo = new JsonObject();
                        if (pjp.getArgs().length > 0) {
                            Object object = pjp.getArgs()[0];
                            String paramValueJSON = new Gson().toJson(object);
                            paramValueInfo = new JsonParser().parse(paramValueJSON).getAsJsonObject();//获取参数
                        }
                        ValidationUnique validationUnique = method.getAnnotation(ValidationUnique.class);
                        String[] keys = validationUnique.key();
                        String[] msgs = validationUnique.msg();
                        int excludeSelf = validationUnique.excludeSelf() ? 1 : 0;
                        String primaryKeyField = validationUnique.primaryKeyField();
                        String primaryKeyColumn = validationUnique.primaryKeyColumn();
                        String groupField = validationUnique.groupField();
                        map.put("excludeSelf", excludeSelf);
                        String primaryKeyValue = "";
                        if (paramValueInfo.has(primaryKeyField)) {
                            primaryKeyValue = paramValueInfo.get(primaryKeyField).getAsString();
                        }
                        if (StringUtil.isEmpty(primaryKeyValue)) {
                            primaryKeyValue = UUID.randomUUID().toString();
                        }
                        map.put("primaryKeyValue", primaryKeyValue);
                        map.put("primaryKeyColumn", primaryKeyColumn);
                        boolean isExistContinue = validationUnique.isExistContinue();
                        if (null != groupField) {
                            for (Field field : fields) {
                                if (groupField.toLowerCase().equals(field.getName().toLowerCase())) {
                                    boolean fieldHasAnnotation = field.isAnnotationPresent(Column.class);
                                    if (fieldHasAnnotation) {
                                        Column fieldAnnotation = field.getAnnotation(Column.class);
                                        String colName = fieldAnnotation.name();
                                        if (paramValueInfo.has(groupField)) {
                                            map.put("groupColumn", colName);
                                            map.put("groupValue", paramValueInfo.get(groupField).getAsString());
                                        }
                                    }
                                }
                            }
                        }
                        List<Map> columnList = new ArrayList<>();
                        for (String key : keys) {
                            Map columnMap = new HashMap(2);
                            String fieldName = key;
                            for (Field field : fields) {

                                if (key.toLowerCase().equals(field.getName().toLowerCase())) {
                                    boolean fieldHasAnnotation = field.isAnnotationPresent(Column.class);
                                    if (fieldHasAnnotation) {
                                        Column fieldAnnotation = field.getAnnotation(Column.class);
                                        String colName = fieldAnnotation.name();
                                        if (paramValueInfo.has(fieldName)) {
                                            columnMap.put("column", colName);
                                            columnMap.put("columnValue", paramValueInfo.get(fieldName).getAsString());
                                            columnList.add(columnMap);
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                        map.put("columnList",columnList);
                        boolean isExist = miService.isFieldValueExist(map);
                        if ((isExistContinue && !isExist)
                                || (!isExistContinue && isExist)) {
                            throw new Exception(msgs[0]);
                        }
                    }
                }
            }
        }
        return pjp.proceed();
    }

    /**
     * 值越小，越优先执行
     */
    @Override
    public int getOrder() {
        return 1;
    }
}
